#include "bString.h"
#include <cstring>
#include <ostream>

void bString::ensure_elements(const unsigned long int num)
{
	const unsigned int len=length();
	if(num<len) return;
	if(ptr)
		ptr=static_cast<char*>(memcpy(new char[num],ptr,len));
	else ptr=new char[num+1];
}

void bString::delete_elements()
{
	delete[]ptr;
}

bString::bString(void):ptr(nullptr)
{
}

bString::bString(const char* cpy):ptr(nullptr)
{
	append(cpy);
}

bString::bString(const char* cpy,unsigned long int p):ptr(nullptr)
{
	append(cpy,p);
}

bString* bString::insert(const unsigned long int pos,const char c)
{
	return insert(pos,&c,1);
}

bString* bString::insert(const unsigned long int pos,const char* src,unsigned long int need)
{
	if(ptr)
	{
		allocate(need);
		char* back=(_used^pos)?static_cast<char*>(memcpy(new char[_used-pos],ptr+pos,_used-pos)):nullptr;
		if(back)
		{
			memcpy(ptr+pos,src,need);
			memcpy(ptr+pos+need,back,_used-pos);
			delete[]back;
		} else memcpy(ptr+pos-1,src,need+1);
	}
	else
	{
		allocate(++need);
		memcpy(ptr,src,need);
	}
	_used+=need;
	ptr[_used-1]='\0';
	return this;
}

bString* bString::insert(const unsigned long int pos,const char* src)
{
	unsigned long int need=strlen(src);
	return insert(pos,src,need);
}

bString* bString::append(const char c)
{
	return append(&c,1);
}

bString* bString::append(const char* src)
{
	return append(src,strlen(src));
}

bString* bString::append(const char* src,unsigned long int p)
{
	return insert(length(),src,p);
}

bString* bString::prepend(const char c)
{
	return prepend(&c,1);
}

bString* bString::prepend(const char* src)
{
	return prepend(src,strlen(src));
}

bString* bString::prepend(const char* src,unsigned long int p)
{
	return insert(0,src,p);
}

const bool bString::operator == ( const char* cmp ) const
{
	if(cmp==ptr) return true;//Are we checking against the same exact string?
	unsigned long int l = strlen(cmp);
	l = ((_used-1)>l)?l:_used-1;
	for(unsigned long int i=0;i<l;i++)
		if(cmp[i]^ptr[i]) return false;
	return true;
}

const bool bString::operator !=  ( const char* cmp ) const
{
	return !operator==(cmp);
}

const bool bString::similar( const char* cmp, unsigned long int l) const
{
	if(cmp==ptr) return true;//Are we checking against the same exact string?
	l = ((_used-1)>l)?l:_used-1;
	for(unsigned long int i=0;i<l;i++)
		if(tolower(cmp[i])^tolower(ptr[i])) return false;
	return true;
}

const bool bString::similar( const char* cmp) const
{
	return similar(cmp,strlen(cmp));
}

unsigned long int bString::find(const char c,unsigned long int start) const
{
	const char* fptr = strchr(ptr+start,c);
	if(fptr)
		return fptr - ptr;
	throw std::exception("Character not found.");
}

unsigned long int bString::find(const char* str,unsigned long int l,unsigned long int start) const
{
	//do code here.
	const char* fptr = strstr(ptr + start,str);
	if(fptr)
		return fptr - ptr;
	throw std::exception("Substring not found.");
}

unsigned long int bString::find(const char* str,unsigned long int start) const
{
	return find(str,strlen(str),start);
}

char& bString::operator[](unsigned long int ind)
{
	return ptr[ind];
}

bString::~bString(void)
{
	empty();
}

bString::operator const char* () const
{
	return ptr;
}

std::ostream& operator << (std::ostream& out,bString* st)
{
	out << (st->operator const char *());
	return out;
}